using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows;
using System.Windows.Controls;

using WozLib.UI.Ink.SketchProperties;
using System.Diagnostics;
using System.Windows.Media.Imaging;
using System.IO;
using WozLib.Net;
using System.Net;
using WozLib.UI.Ink.SketchObjects;
using System.Windows.Input;

namespace WozLib.UI.Ink.SketchElements
{
  public class SketchButton : Canvas, ISketchObject
  {
    public delegate void SketchButtonCreatedDelegate(SketchButton sketchButton);
    public static event SketchButtonCreatedDelegate SketchButtonCreated;

    public static SketchButton FromButtonWozObject(ButtonSketchObject buttonWozObject)
    {
      SketchPropertyCollection wozPropertyCollection = new SketchPropertyCollection();
      wozPropertyCollection.WozProperties = buttonWozObject.WozProperties;

      return new SketchButton(buttonWozObject.WozID, wozPropertyCollection);
    }

    public event TextChangedEventHandler TextChanged;

    private static TextBlock GetDefaultTextBlock(Canvas canvas, Button button)
    {
      return GetDefaultTextBlock(new Rect(new Point(0.0, 0.0), new Point(1.0, 1.0)), canvas, button, "button");
    }

    private static TextBlock GetDefaultTextBlock(Rect rect, Canvas canvas, Button button, string text)
    {

      TextBlock textBlock = new TextBlock();
      textBlock.FontSize = 12.0;
      textBlock.FontFamily = new FontFamily("Verdana");
      textBlock.TextWrapping = TextWrapping.Wrap;
      textBlock.Text = text;
      textBlock.Foreground = Brushes.Black;
      textBlock.SetValue(Canvas.LeftProperty, 0.0);
      textBlock.SetValue(Canvas.TopProperty, 0.0);
      textBlock.Width = rect.Width;
      textBlock.Height = rect.Height;
      textBlock.TextAlignment = TextAlignment.Center;
      button.Width = rect.Width;
      button.Height = rect.Height;
      //button.SetValue(InkCanvas.LeftProperty, rect.X);
      //button.SetValue(InkCanvas.TopProperty, rect.Y);
      canvas.Width = rect.Width;
      canvas.Height = rect.Height;
      canvas.SetValue(InkCanvas.LeftProperty, rect.X);
      canvas.SetValue(InkCanvas.TopProperty, rect.Y);
      //textBox.BorderBrush = Brushes.Transparent;
      if (false)
      {
        //textBox.BorderThickness = 0.0;
      }
      else
      {
        //textBox.BorderThickness = 0.0;
        textBlock.Background = Brushes.Transparent;
      }
      button.Content = textBlock;
      //canvas.Children.Add(textBlock);
      return textBlock;
    }

    bool _textChanging = false;

    public TextBlock TextBlock
    {
      get { return _TextBlock; }
      set { _TextBlock = value; }
    } private TextBlock _TextBlock;

    public Button Button
    {
      get { return _Button; }
      set { _Button = value; }
    } private Button _Button;

    public SketchButton()
      : this(new Rect(new Point(0.0,0.0),new Point(1.0,1.0)),null)
    {
    }

    public SketchButton(Rect rect, SketchObjectRegistry wozObjectRegistry) : this (rect,wozObjectRegistry, null)
    {
    }

    public SketchButton(Rect rect, SketchObjectRegistry wozObjectRegistry, string text)
    {
      Button = new Button();
      Button.SetValue(Canvas.LeftProperty, 0.0);
      Button.SetValue(Canvas.TopProperty, 0.0);
      this.Children.Add(Button);

      // create the textblock that will be the content of this button
      // Alternatively we could just let users construct the contents of the button from
      // the clipboard
      if (text != null)
      {
        TextBlock = GetDefaultTextBlock(rect, this, Button, text);
      }
      else
      {
        TextBlock = GetDefaultTextBlock(rect, this, Button, "button");
      }

      // register this object
      if (wozObjectRegistry != null)
      {
        wozObjectRegistry.RegisterObject(this);
      }
      else
      {
        
      }

      TextBlock.Visibility = Visibility.Visible;

      // Set all of our WozPropertyCollection properties

      FontSizeSketchProperty fontSizeProperty = new FontSizeSketchProperty(TextBlock.FontSize, WozPropertyType.FontSize);
      this.SetProperty(fontSizeProperty);

      StringSketchProperty fontWozProperty = new StringSketchProperty(TextBlock.FontFamily.ToString(), WozPropertyType.Font);
      this.SetProperty(fontWozProperty);

      if (TextBlock.Text != null)
      {
        StringSketchProperty stringWozProperty = new StringSketchProperty(TextBlock.Text, WozPropertyType.Text);
        this.SetProperty(stringWozProperty);
      }

      if (TextBlock.Background is SolidColorBrush)
      {
        ColorSketchProperty colorWozPropertyFill = new ColorSketchProperty((TextBlock.Background as SolidColorBrush).Color, WozPropertyType.FillColor);
        this.SetProperty(colorWozPropertyFill);
      }
      //else if (TextBlock.Background is ImageBrush)
      //{
      //  StringWozProperty stringWozProperty = new StringWozProperty(imageUrl,WozPropertyType.FillImageUrl);
      //  this.SetProperty(stringWozProperty);
      //}

      if (TextBlock.Foreground is SolidColorBrush)
      {
        ColorSketchProperty colorWozPropertyFill = new ColorSketchProperty((TextBlock.Foreground as SolidColorBrush).Color, WozPropertyType.ForegroundColor);
        this.SetProperty(colorWozPropertyFill);
      }
      //else if (TextBlock.Foreground is ImageBrush)
      //{
      //  StringWozProperty stringWozProperty = new StringWozProperty(imageUrl, WozPropertyType.ForegroundImageUrl);
      //  this.SetProperty(stringWozProperty);
      //}

      // set the points
      RectGeometrySketchProperty rectGeometryWozProperty = new RectGeometrySketchProperty(rect, WozPropertyType.RectGeometry);
      this.SetProperty(rectGeometryWozProperty);

      // set in front of ink
      BooleanSketchProperty behindInkProperty = new BooleanSketchProperty(false, WozPropertyType.BehindInk);
      this.SetProperty(behindInkProperty);

      if (SketchButtonCreated != null)
      {
        SketchButtonCreated(this);
      }
    }

    public SketchButton(long id, SketchPropertyCollection wozPropertyCollection)
      : this(id, wozPropertyCollection, null)
    {
    }

    public SketchButton(long id, SketchPropertyCollection wozPropertyCollection, SketchObjectRegistry wozObjectRegistry)
      : base()
    {
      Button = new Button();
      Button.SetValue(Canvas.LeftProperty, 0.0);
      Button.SetValue(Canvas.TopProperty, 0.0);
      this.Children.Add(Button);

      TextBlock = GetDefaultTextBlock(this, Button);

      TextBlock.Visibility = Visibility.Visible;

      // assign our ID before we doing anything else
      this._WozID = id;

      // overwrite our blank collection with the provided one
      this._WozPropertyCollection = wozPropertyCollection;

      // all of our properties can be set this way
      SetProperty(wozPropertyCollection.WozProperties);

      // register this object
      if (wozObjectRegistry != null)
      {
        wozObjectRegistry.RegisterObjectWithExisitingId(this);
      }

      if (SketchButtonCreated != null)
      {
        SketchButtonCreated(this);
      }
    }

    #region IWozObject Members

    // our private way of holding an ID
    private long _WozID = long.MinValue;

    public long WozID
    {
      get 
      {
        return _WozID;
      }
      set
      {
        _WozID = value;
      }
    }

    // our private way of holding properties
    protected SketchPropertyCollection _WozPropertyCollection = new SketchPropertyCollection();

    // You should update your properties to reflect the actualy state of your underlying object
    // i.e if your current color property says Black, but your stroke actually had its color
    // changed to Red recently - change the color property to red
    public void SyncProperties()
    {
      SyncProperties(_WozPropertyCollection);
    }

    // You should update your properties to reflect the actualy state of your underlying object
    // i.e if your current color property says Black, but your stroke actually had its color
    // changed to Red recently - change the color property to red
    protected void SyncProperties(SketchPropertyCollection wozPropertyCollection)
    {
      RectGeometrySketchProperty rectGeometryWozProperty = new RectGeometrySketchProperty(
        new Rect((double)GetValue(InkCanvas.LeftProperty),(double)GetValue(InkCanvas.TopProperty),this.Width,this.Height),
        WozPropertyType.RectGeometry);
      SetProperty(rectGeometryWozProperty);

      this.SetProperty(new StringSketchProperty(TextBlock.Text, WozPropertyType.Text));
    }

    // Set the property, but also make the corresponding change to the underlying object
    // i.e. if the color property is set on a stroke, actually change the drawing attributes
    public void SetProperty(WozLib.UI.Ink.SketchProperties.SketchProperty wozProperty)
    {
      _WozPropertyCollection.SetProperty(wozProperty);

      UpdateProperty(wozProperty);
    }

    private void UpdateProperty(WozLib.UI.Ink.SketchProperties.SketchProperty wozProperty)
    {
      try
      {
        // Figure out what we should with this property
        switch (wozProperty.WozPropertyType)
        {
          case WozPropertyType.Font:
            TextBlock.FontFamily = new FontFamily((wozProperty as StringSketchProperty).Data);
            break;
          case WozPropertyType.FontSize:
            TextBlock.FontSize = (wozProperty as FontSizeSketchProperty).Data;
            break;
          case WozPropertyType.FillColor:
            TextBlock.Background = new SolidColorBrush((wozProperty as ColorSketchProperty).Data);
            break;
          case WozPropertyType.ForegroundColor:
            TextBlock.Foreground = new SolidColorBrush((wozProperty as ColorSketchProperty).Data);
            break;
          case WozPropertyType.FillImageUrl:
            try
            {
              // try to create an image from the url
              BitmapImage bitmapImage = new BitmapImage(new Uri((wozProperty as StringSketchProperty).Data));


              // make the rectangle's fill the image
              ImageBrush ib = new ImageBrush(bitmapImage);
              TextBlock.Background = ib;
              this.InvalidateVisual();
              //Rectangle.InvalidateVisual();
            }
            catch (Exception ex)
            {
              Debug.WriteLine(ex);
            }
            break;
          case WozPropertyType.RectGeometry:
            Rect rect = (wozProperty as RectGeometrySketchProperty).Rect;

            this.SetValue(InkCanvas.LeftProperty, rect.X);
            this.SetValue(InkCanvas.TopProperty, rect.Y);
            this.SetValue(Canvas.LeftProperty, rect.X);
            this.SetValue(Canvas.TopProperty, rect.Y);
            this.TextBlock.Width = rect.Width;
            this.TextBlock.Height = rect.Height;
            this.Button.Width = rect.Width;
            this.Button.Height = rect.Height;
            this.Width = rect.Width;
            this.Height = rect.Height;
            break;
          case WozPropertyType.Text:
            if (!_textChanging)
            {
              _textChanging = true;

              string text = (wozProperty as StringSketchProperty).Data;

              TextBlock.Text = text;

              _textChanging = false;
            }
            break;
          case WozPropertyType.Bounds:
            // don't know how right now
            break;

          default:
            // This shouldn't happen
            Debug.WriteLine(this.ToString() + " doesn't know what to do with a " + wozProperty.WozPropertyType.ToString());
            break;
        }
      }
      catch (Exception ex)
      {
        Debug.WriteLine("SketchLine: Property Setting Failed: " + ex.ToString());
      }
    }

    public void SetProperty(IEnumerable<WozLib.UI.Ink.SketchProperties.SketchProperty> wozProperties)
    {
      foreach (SketchProperty wozProperty in wozProperties)
      {
        SetProperty(wozProperty);
      }
    }

    // just return the specified property
    public SketchProperty GetProperty(WozPropertyType wozPropertyType)
    {
      return _WozPropertyCollection.GetProperty(wozPropertyType);
    }

    // WozPropertyCollection makes a copy for us
    public IEnumerable<SketchProperty> GetProperties()
    {
      return _WozPropertyCollection.WozProperties;
    }

    // Make sure we create the WozObject from the appropriate derived class (LineWozObject)
    public SketchObject GetWozObject()
    {
      return new ButtonSketchObject(WozID, GetProperties());
    }

    #endregion

    #region IWozObject Members


    // maybe i should just check to see if this is in our bounds?
    public bool ShouldErase(Point pointRelativeToUie)
    {
      if (this.InputHitTest(pointRelativeToUie) != null)
      {
        return true;
      }
      else
      {
        return false;
      }
    }

    #endregion
  }
}
